﻿
namespace Common.Algorithm.Core.LocalTest;



/// <summary>
///  minF1=Math.Sum<1,N>(xi*xi)
///  100≥xi≥-100，N=10．全局最小在x=(0，0，…，0)处为0． 
/// </summary>
public class MultiFactorSumFunction1 : ITargetFunction
{
    /// <summary>
    /// 一个自变量的二进制长度
    /// </summary>
    public int binaryLen { get; set; } = 16;

    /// <summary>
    /// 整个序列长度
    /// </summary>
    public int sequenceLen { get; set; }


    /// <summary>
    /// 定义域 x1 x2  
    /// </summary>
    public IList<double[]> ranges { get; set; } = new List<double[]>() {
            new double[] {  -100d, 100d },
            new double[] {  -100d, 100d },
        };

    /// <summary>
    /// 
    /// </summary>
    public MultiFactorSumFunction1()
    {
        //ranges决定自变量数量  一个自变量采用16位二进制编码  故序列总长为 n*16  
        sequenceLen = ranges.Count * binaryLen;// _sequenceLen;
    }


    /// <summary> 
    /// 
    /// </summary>
    /// <param name="ranges"></param>
    /// <returns></returns>
    public Func<double[], double> GenMathFunction()
    {
        Func<double[], double> func = (pnt) =>
        {
            var xs = pnt.ToList();
            var sum = 0d;
            foreach (var xi in xs)
            {
                sum += xi * xi;
            }
            double res = sum;
            return res;
        };
        return func;
    }

    /// <summary>
    /// 二进制转码  采用16位
    /// </summary>
    /// <param name="values"></param>
    /// <returns></returns>
    public double[] BinaryDecode(int[] values)
    {
        List<double> doubles = new List<double>();

        for (int i = 0; i < ranges.Count; i++)
        {
            double[] argument = ranges[i];//一个自变量定义域的范围数组
            int len = binaryLen;
            List<int> bins = values.ToList().GetRange(len * i, len);
            var bin = Convert.ToInt16(string.Join("", bins), 2);
            var num = argument.Average() + bin * (argument[1] - argument[0]) / (Math.Pow(2, len) - 1);//2^16-1=65534
            doubles.Add(num);
        }
        return doubles.ToArray();
    }
}


/// <summary>
///  minF4=Math.Sum<1,N>(100*(xi1-xi*xi)*(xi1-xi*xi)+(xi-1)*(xi-1))
///  30≥xi≥-30，N=50．全局最小在x=(1，1，…，1)处为0． 
/// </summary>
public class MultiFactorSumFunction4 : ITargetFunction
{
    /// <summary>
    /// 一个自变量的二进制长度
    /// </summary>
    public int binaryLen { get; set; } = 16;

    /// <summary>
    /// 整个序列长度
    /// </summary>
    public int sequenceLen { get; set; }

    /// <summary>
    /// 定义域 x1 x2  
    /// </summary>
    public IList<double[]> ranges { get; set; } = new List<double[]>() {
            new double[] {  -30d, 30d },
            new double[] {  -30d, 30d },
        };

    /// <summary>
    /// 
    /// </summary>
    public MultiFactorSumFunction4()
    {
        //ranges决定自变量数量  一个自变量采用16位二进制编码  故序列总长为 n*16  
        sequenceLen = ranges.Count * binaryLen;// _sequenceLen;
    }


    /// <summary> 
    /// 
    /// </summary>
    /// <param name="ranges"></param>
    /// <returns></returns>
    public Func<double[], double> GenMathFunction()
    {
        Func<double[], double> func = (pnt) =>
        {
            var xs = pnt.ToList();
            var sum = 0d;
            for (int i = 0; i < ranges.Count - 1; i++)
            {
                var xi = xs[i];
                var xi1 = xs[i + 1];
                var unit = 100 * Math.Pow(xi1 - xi * xi, 2) + Math.Pow(xi - 1, 2);
                sum += unit;
            }
            double res = sum;
            return res;
        };
        return func;
    }

    /// <summary>
    /// 二进制转码  采用16位
    /// </summary>
    /// <param name="values"></param>
    /// <returns></returns>
    public double[] BinaryDecode(int[] values)
    {
        List<double> doubles = new List<double>();

        for (int i = 0; i < ranges.Count; i++)
        {
            double[] argument = ranges[i];//一个自变量定义域的范围数组
            int len = binaryLen;
            List<int> bins = values.ToList().GetRange(len * i, len);
            var bin = Convert.ToInt16(string.Join("", bins), 2);
            var num = argument.Average() + bin * (argument[1] - argument[0]) / (Math.Pow(2, len) - 1);//2^16-1=65534
            doubles.Add(num);
        }
        return doubles.ToArray();
    }
}

